package org.movee.net.cfg.parser.parser.xorplus;

import org.movee.net.cfg.parser.domain.model.AddressFamilyType;
import org.movee.net.cfg.parser.domain.model.ConfigModel;
import org.movee.net.cfg.parser.domain.model.InterfaceStatus;
import org.movee.net.cfg.parser.domain.model.InterfaceType;
import org.movee.net.cfg.parser.utils.OrikaSupplier;
import ma.glasnost.orika.MapperFacade;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.TreeMap;

/**
 *
 *
 * @author 
 */
public class XorplusConfigModelConverter implements Converter<XorplusConfigModel, ConfigModel> {

    private final MapperFacade orika = OrikaSupplier.ORIKA;

    @Nullable
    @Override
    public ConfigModel convert(@NonNull XorplusConfigModel source) {

        // netware
        ConfigModel.Netware netware = createNetware(source.getNetware());

        ConfigModel.Bgp bgp = createBgp(source.getBgp());

        Map<String, ConfigModel.IpUnit> ipUnits = new TreeMap<>();
        Map<String, ConfigModel.InterfaceUnit> intfUnits = new TreeMap<>();

        for (XorplusConfigModel.Interface intf : source.getIntfs().values()) {
            ConfigModel.Interface dstIntf = createInterface(intf);

            ConfigModel.InterfaceUnit intfUnit = new ConfigModel.InterfaceUnit();
            intfUnit.setIntf(dstIntf);
            if (StringUtils.hasLength(intf.getAd8023())) {
                intfUnit.setPIntf(intf.getAd8023());
            } else if (intf.getNativeVlanId() != null) {
                XorplusConfigModel.Vlan vlan = source.getVlan(intf.getNativeVlanId());
                if (vlan != null && StringUtils.hasLength(vlan.getL3Interface())) {
                    intfUnit.setPIntf(vlan.getL3Interface());
                }
            }

            intfUnits.put(dstIntf.getName(), intfUnit);
        }

        for (XorplusConfigModel.VlanInterface intf : source.getVlanIntfs().values()) {
            ConfigModel.Interface dstIntf = createInterface(intf);
            ConfigModel.InterfaceUnit intfUnit = new ConfigModel.InterfaceUnit();
            intfUnit.setIntf(dstIntf);

            for (XorplusConfigModel.VlanInterfaceIp ip : intf.getIntfIps()) {
                ConfigModel.Ip dstIp = createIp(ip);

                String ipAddr = dstIp.getIpAddress();
                ConfigModel.IpUnit ipUnit = createIpUnit(dstIp, dstIntf.getName());
                ipUnits.put(ipAddr, ipUnit);

                if (ipAddr.contains(".")) {
                    intfUnit.getIpv4s().add(ipAddr);
                } else if (ipAddr.contains(":")) {
                    intfUnit.getIpv6s().add(ipAddr);
                }
            }

            intfUnits.put(dstIntf.getName(), intfUnit);
        }

        for (ConfigModel.InterfaceUnit intfUnit : intfUnits.values()) {
            if (StringUtils.hasLength(intfUnit.getPIntf())) {
                ConfigModel.InterfaceUnit parent = intfUnits.get(intfUnit.getPIntf());
                if (parent != null) {
                    parent.getCIntfs().add(intfUnit.getIntf().getName());
                }
            }
        }

        return new ConfigModel()
                .setMgmtIp(source.getMgmtIp())
                .setTimestamp(source.getTimestamp())
                .setNetware(netware)
                .setInterfaces(intfUnits)
                .setIps(ipUnits)
                .setBgp(bgp);
    }

    private ConfigModel.Netware createNetware(XorplusConfigModel.Netware netware) {
        return orika.map(netware, ConfigModel.Netware.class);
    }

    private ConfigModel.Interface createInterface(XorplusConfigModel.Interface intf) {
        return orika.map(intf, ConfigModel.Interface.class);
    }

    private ConfigModel.Interface createInterface(XorplusConfigModel.VlanInterface intf) {
        ConfigModel.Interface dstIntf = orika.map(intf, ConfigModel.Interface.class);
        dstIntf.setAdminStatus(InterfaceStatus.UP.name());
        dstIntf.setInterfaceType(InterfaceType.VLAN.name());
        return dstIntf;
    }

    private ConfigModel.Ip createIp(XorplusConfigModel.VlanInterfaceIp ip) {
        ConfigModel.Ip dstIp = orika.map(ip, ConfigModel.Ip.class);
        dstIp.setFamily(AddressFamilyType.IPV4.name());
        return dstIp;
    }

    private ConfigModel.IpUnit createIpUnit(ConfigModel.Ip ip, String intfName) {
        return new ConfigModel.IpUnit().setIp(ip).setIntf(intfName);
    }

    private ConfigModel.Bgp createBgp(XorplusConfigModel.Bgp bgp) {
        if (bgp == null) {
            return null;
        }

        ConfigModel.Bgp dstBgp = orika.map(bgp, ConfigModel.Bgp.class);

        dstBgp.getPeers().clear();
        for (XorplusConfigModel.BgpPeer peer : bgp.getPeers().values()) {
            ConfigModel.BgpPeer dstPeer = orika.map(peer, ConfigModel.BgpPeer.class);
            dstBgp.getPeers().put(dstPeer.getPeerIp(), dstPeer);
        }
        return dstBgp;
    }
}
